//! 定义插件的运行时上下文

use std::any::Any;
use std::collections::HashMap;
use std::sync::{Arc, Mutex};

use crate::core::beans::bean::IDestructible;
use crate::core::manifest::{ContributeDefinition, ContributionPointDefinition, ExpansionManifest};
use crate::core::services::contribution_keyword_manager::ContributionKeywordManager;
use crate::core::services::event_manager::{EventManager, expansion_lifecycle_event_names};
use crate::core::services::extension_manager::ExtensionManager;
use crate::core::services::manifest_manager::ManifestManager;
use crate::core::services::protocols::*;

fn fail(message: &str) {
    // 在开发环境中 panic，在生产环境中可以考虑只打印日志
    panic!("{}", message);
}

// --- ActivateContext --- 

/// 插件激活时收到的上下文，提供与内核交互的各种接口。
/// 对应 `ai-server` 的 `ActivateContext`
pub struct ActivateContext {
    // --- 依赖注入的服务 ---
    manifest_manager: Arc<ManifestManager>,
    extension_manager: Arc<ExtensionManager>,
    contribution_manager: Arc<ContributionKeywordManager>,
    event_manager: Arc<EventManager>,

    // --- 插件自身的状态 ---
    pub manifest: ExpansionManifest,
    stage: Mutex<String>,
    disposers: Mutex<Vec<Disposer>>,
    
    // --- 注入的依赖上下文 ---
    pub services: HashMap<String, Arc<dyn Any + Send + Sync>>,
}

impl ActivateContext {
    pub fn new(
        manifest: ExpansionManifest,
        manifest_manager: Arc<ManifestManager>,
        extension_manager: Arc<ExtensionManager>,
        contribution_manager: Arc<ContributionKeywordManager>,
        event_manager: Arc<EventManager>,
        services: HashMap<String, Arc<dyn Any + Send + Sync>>,
    ) -> Self {
        Self {
            manifest,
            manifest_manager,
            extension_manager,
            contribution_manager,
            event_manager,
            services,
            stage: Mutex::new("".to_string()),
            disposers: Mutex::new(Vec::new()),
        }
    }

    pub fn get_context<T: 'static + Send + Sync>(&self, name: &str) -> Option<Arc<T>> {
        self.services
            .get(name)
            .and_then(|service| service.clone().downcast::<T>().ok())
    }

    pub fn set_stage(&self, stage: &str) {
        *self.stage.lock().unwrap() = stage.to_string();
    }
}

impl IDestructible for ActivateContext {
    fn destructor(&self) {
        let mut disposers = self.disposers.lock().unwrap();
        for disposer in disposers.drain(..) {
            disposer();
        }
    }
}

impl IExpansionBaseContext for ActivateContext {
    fn get_extension(&self, name: &str) -> Option<Arc<dyn Any + Send + Sync>> {
        // TODO: 实现断言 `assert_is_dependent_valid`
        // if !self.manifest_manager.get_assertion().assert_is_dependent_valid(&self.manifest, name) {
        //     return None;
        // }
        self.extension_manager.get_api(name)
    }

    fn register_contribution_keyword(
        &self,
        name: &str,
        impl_bean: Arc<dyn IContributionKeyword>,
    ) {
        // TODO: 实现断言
        // assert_contribution_keyword_name_is_valid(...)
        // assert_contribution_keyword_is_defined(...)
        let disposer = self
            .contribution_manager
            .implement_contribution_keyword(name, impl_bean);
        self.add_disposer(disposer);
    }

    fn get_contribution_keyword_impl(&self, name: &str) -> Option<Arc<dyn IContributionKeyword>> {
        // TODO: 实现断言 `assert_contribution_keyword_is_defined`
        self.contribution_manager.get_contribution_keyword_impl(name)
    }

    fn add_disposer(&self, disposer: Disposer) {
        self.disposers.lock().unwrap().push(disposer);
    }

    fn add_contribution_points(
        &self,
        contribution_points: HashMap<String, Vec<ContributionPointDefinition>>,
    ) {
        // TODO: 实现断言 `assert_manifest_contribution_points_is_valid`
        // self.manifest.dynamic_contribution_points = Some(merged_points);
        if *self.stage.lock().unwrap() != "beforeActivate" {
            let payload = Arc::new((self.manifest.name.clone(), contribution_points));
            self.event_manager.dispatch(
                expansion_lifecycle_event_names::ON_DYNAMIC_CONTRIBUTION_POINTS_ADDED,
                payload,
            );
        }
    }

    fn add_contributes(&self, contributes: HashMap<String, Vec<ContributeDefinition>>) {
        // TODO: 实现断言 `assert_manifest_contribute_is_valid`
        // self.manifest.dynamic_contributes = Some(merged_contributes);
        if *self.stage.lock().unwrap() != "beforeActivate" {
            let payload = Arc::new((self.manifest.name.clone(), contributes));
            self.event_manager.dispatch(
                expansion_lifecycle_event_names::ON_DYNAMIC_CONTRIBUTES_ADDED,
                payload,
            );
        }
    }

    fn remove_contributes(&self, keyword: &str, name: &str) {
        // TODO: 实现从 dynamic_contributes 中移除
        let removed: HashMap<String, Vec<ContributeDefinition>> = HashMap::new(); // 模拟移除
        if *self.stage.lock().unwrap() != "beforeActivate" {
            let payload = Arc::new((self.manifest.name.clone(), removed));
            self.event_manager.dispatch(
                expansion_lifecycle_event_names::ON_DYNAMIC_CONTRIBUTES_REMOVED,
                payload,
            );
        }
    }

    fn remove_contribution_points(&self, keyword: &str, name: &str) {
        // TODO: 实现从 dynamic_contribution_points 中移除
        let removed: HashMap<String, Vec<ContributionPointDefinition>> = HashMap::new(); // 模拟移除
        if *self.stage.lock().unwrap() != "beforeActivate" {
            let payload = Arc::new((self.manifest.name.clone(), removed));
            self.event_manager.dispatch(
                expansion_lifecycle_event_names::ON_DYNAMIC_CONTRIBUTION_POINTS_REMOVED,
                payload,
            );
        }
    }
}


// --- RequestContributionContext ---

/// 请求贡献时的上下文
/// 对应 `ai-server` 的 `RequestContributionContext`
pub struct RequestContributionContext {
    manifest: ExpansionManifest,
}

impl RequestContributionContext {
    pub fn new(manifest: ExpansionManifest) -> Self {
        Self { manifest }
    }
}

impl IRequestContributionContext for RequestContributionContext {
    fn contributor(&self) -> &str {
        &self.manifest.name
    }

    fn dependencies(&self) -> Vec<String> {
        self.manifest
            .dependencies
            .as_ref()
            .map_or(Vec::new(), |deps| deps.keys().cloned().collect())
    }
}